﻿/**
 * 模块名称
 */
const moduleName = "pao";
/**
 * 全局插件属性名
 */
const globalAddnPropertyName = "globalAddons";

/**
 * 定义全局变量
 */
global[globalAddnPropertyName] = {};

/**
* 类型(构造函数)
*/
export interface type<T> {
    new(): T
}

/** 获取对象类型 */
export function getType<T>(obj: T): type<T> {
    return <type<T>>obj.constructor;
}

/**
 * 字符串格式化
 * @param str 字符串
 * @param args 参数
 */
export function format(str: string, ...args: any[]){
    return str.replace(/\{(\d+)\}/g,function(s,i){
        return args[i];
    });
}

/**
* 新建Guid
*/
export function newGuid(): string {
    let guid = "{";
    for (let i = 1; i <= 32; i++) {
        let n = Math.floor(Math.random() * 16.0).toString(16);
        guid += n;
        if ((i == 8) || (i == 12) || (i == 16) || (i == 20))
            guid += "-";

    }
    return guid + "}";
}
/**
* 获取当前日期字符串（精确到日）
*/
export function getCurrentDateString(): string {
    let today = new Date();
    let timeString = today.getFullYear() + "/" + today.getMonth() + "/" + today.getDay();
    return timeString;
}

/**
* 获取当前时间字符串（精确到毫秒）
*/
export function getCurrentTimeString(): string {
    let today = new Date();
    return `${today.getFullYear()}/${today.getMonth()}/${today.getDay()} ${today.getHours()}:${today.getMinutes()}:${today.getSeconds()}.${today.getMilliseconds()}`;
}

export class proxy {
    /**
    * 创建透明代理
    * @param origionObject 原始对象
    * @param methodHandler 代理方法
    */
    static createTransparentProxy(origionObject: new () => any, methodHandler: (methodName: string, args: any[]) => any): any {
        let proxyObject = {};
        let proxyType = origionObject.prototype;
        let funcNameList: string[] = [];
        // 将函数名赋值到数组，进行闭包处理
        for (var func in proxyType) {
            var prop = proxyType[func];
            if (prop instanceof Function) {
                funcNameList.push(func);
            }
        }
        // 通过函数名数组定义代理的方法
        for (let funcName of funcNameList) {
            proxyObject[funcName] = (...proxyArgs: any[]): any => {
                return methodHandler(funcName, proxyArgs);
            }
        }

        return proxyObject;
    }

    /**
    * 在原对象上创建透明代理方法
    * @param origionObject 原始对象
    * @param methodHandler 代理方法
    */
    static buildTransparentProxyObject(destObject: Object, origionObject: type<any>, methodHandler: (methodName: string, args: any[]) => any) {
        let proxyType = origionObject.prototype;
        let funcNameList: string[] = [];
        let baseObj = new baseObject();

        // 将函数名赋值到数组，进行闭包处理
        for (var func in proxyType) {
            /** 只代理非baseObject类型中的方法 */
            if (!baseObj[func]) {
                var prop = proxyType[func];
                if (prop instanceof Function) {
                    funcNameList.push(func);
                }
            }
        }
        // 通过函数名数组定义代理的方法
        for (let funcName of funcNameList) {
            destObject[funcName] = (...proxyArgs: any[]): any => {
                return methodHandler(funcName, proxyArgs);
            }
        }
    }
}

export class reflect {
    /**
    * 指定类型
    * @param originObject 要指定类型的原始对象
    * @param targetType 目标类型
    */
    static assignType(originObject: any, targetType: Function) {
        let newMethod: any = targetType;
        originObject.__proto__ = newMethod.prototype;
        originObject.__proto__.constructor = newMethod;

        // 调用构造方法，并复制数据到原始对象，这种方法相对call来说，会复制装饰器修饰的方法
        let newObj = new newMethod();
        reflect.propertyCopy(originObject, newObj);

        // 调用事件
        if (originObject.onAssignedType) {
            originObject.onAssignedType();
        }
    }
    /**
    * 获取类名
    * @param objClass 对象类型
    */
    static getTypeFullName(objClass: any): string {
        let func: Function;
        if (objClass instanceof Function) {
            func = objClass;
        }
        else if (objClass && objClass.constructor) {
            func = objClass.constructor;
        }
        if (func) {
            let strFun = func.toString();
            let className = strFun.substr(0, strFun.indexOf('('));
            className = className.replace('function', '');
            className = className.replace(/(^\s*)|(\s*$)/ig, '');
            if (func.prototype.$module) {
                return func.prototype.$module + "." + className;
            } else {
                return className;
            }
        }
        if (objClass.name) {
            return objClass.name;
        }
        return typeof objClass;
    }

    /**
        * 属性赋值，将源对象的所有属性复制到目标对象
        * @param destObject 目标对象
        * @param srcObject 源对象
        * @param coverDefinedField 覆盖已经有数值的字段
        */
    static propertyCopy(destObject: Object, srcObject: Object, coverDefinedField: boolean = false): void {
        for (let property in srcObject) {
            // 只复制没有设置的属性
            if (coverDefinedField || !destObject[property]) {
                destObject[property] = srcObject[property];
            }
        }
    }
}

/**
* 用户令牌
*/
export class userToken {
    /**
    * 用户名
    */
    name: string;
    /**
    * 密码，经过MD5运算
    */
    password: string;
}

/**
* 当前用户
*/
export let currentUser: userToken;

/**
* Json请求
*/
export interface remoteHeader {
    userID?: string;
    transactionID?: string;
    password?: string;
}

/**
* 远程请求
*/
export interface remoteRequest {
    serviceName: string;
    functionName: string;
    header?: remoteHeader;
    args?: any;
}

/**
* 类型名称属性名
*/
export const typeNamePropertyName: string = "$type";

/**
* 基础插件对象:所有实体对象的基类，实现了ID，Name和Description，其中ID是对象的唯一标识，Name是对象的好记的名称，Description是对象的描述
*/
export interface addonObject {
    /** 类型名称，序列化/反序列化时用于保存类型的原型 */
    $type?: string;
    /** 工厂 */
    $factory?: proxyFactory;
    /** 元数据：模块/命名空间名称 */
    $module?: string;
    /** 元数据：插件名称 */
    $addonName?: string;
    /** 元数据：插件描述 */
    $addonDescription?: string;
    /** 扩展属性 */
    [id: string]: any

    /**
        * 事件：指定类型后
        */
    onAssignedType?(): void;
}

//******************** 装饰器 *********************
/**
 * 插件装饰器：用此装饰过的插件会将构造函数添加到插件类型列表中，便于检索
 * @param name 插件名称
 * @param description 插件描述
 */
export function addon(name: string, description?: string, moduleName?: string) {
    return function (target: any) {
        target.prototype.$module = moduleName;
        target.prototype.$addonName = name;
        target.prototype.$addonDescription = description;

        let fullName = reflect.getTypeFullName(target);
        log(`插件${fullName}加载成功.`);
        global[globalAddnPropertyName][fullName] = target;
    };
}

//********************   实体对象   *********************
/**
 * 基础插件对象:所有实体对象的基类，实现了ID，Name和Description，其中ID是对象的唯一标识，Name是对象的好记的名称，Description是对象的描述
 */
@addon("基础插件对象",
    "所有实体对象的基类，实现了ID，Name和Description，其中ID是对象的唯一标识，Name是对象的好记的名称，Description是对象的描述",
    moduleName)
export class baseObject implements addonObject {
    /** 类型名称，序列化/反序列化时用于保存类型的原型 */
    $type?: string;
    /** 类型 */
    $constructor?: type<addonObject>;
    /** 元数据：模块/命名空间名称 */
    $module?: string;
    /** 元数据：插件名称 */
    $addonName?: string;
    /** 元数据：插件描述 */
    $addonDescription?: string;
    /** 扩展属性 */
    [id: string]: any;
    /**
     * 事件：指定类型后
     */
    onAssignedType?(): void { }

    /**
     * 从Origion生成
     * @param origion 原始对象
     */
    from?(origion: any ) {
        reflect.propertyCopy(origion, this);
    }
}

/**
 * 工厂
 */
export interface factory {
    /**
     * 获取值
     */
    getValue?(): any;
}

export function isFactory(obj: any): obj is factory {
    return (<factory>obj).getValue !== undefined;
}

/**
 * 获取对象
 * @param obj 对象，可能是实例或工厂
 */
export function getObject<T>(obj: T | factory) : T {
    if (isFactory(obj)) {
        return obj.getValue();
    } else {
        return obj;
    }
}

/**
 * 代理工厂: 通过代理方式实现的工厂
 */
@addon("代理工厂",
    "通过代理方式实现的工厂",
    moduleName)
export class proxyFactory extends baseObject implements factory {
    /** 
     * 工厂的目标对象 
     */
    destType: baseObject;
    /**
     * 内部对象
     */
    protected innerObject?: any = {};

    constructor(objectType: type<any>) {
        super();
        if (objectType) {
            this.destType = new objectType();
        }
    }

    proxyMethod?(methodName: any, args: any): any {
        return this.innerObject[methodName].apply(args);
    }

    getValue?(): any {
        if(!this.innerObject) {
            this.innerObject = {};
        }

        /** 指定类型后建立代理对象 */
        proxy.buildTransparentProxyObject(this.innerObject, getType<any>(this.destType), (methodName: any, args: any) => {
            return this.proxyMethod(methodName, args);
        });
        return this.innerObject;
    }
}

/**
 * 对象工厂: 对象的直接引用
 */
@addon("对象工厂",
    "对象的直接引用",
    moduleName)
export class objectFactory extends baseObject implements factory {
    constructor(public objectReference?: any) {
        super();
    }

    getValue?(): any {
        return this.objectReference;
    }
}

/**
 * Json工厂: 通过JSONP字符串创建对象
 */
@addon("Json工厂",
    "通过JSONP字符串创建对象",
    moduleName)
export class jsonFactory extends baseObject implements factory {
    constructor(public jsonString?: string) {
        super();
    }

    getValue?(): any {
        if (!this.jsonString)
            return addonDeserialize(this.jsonString);
        return undefined;
    };
}

/**
 * 插件工厂：根据插件ID获取插件
 */
@addon("插件工厂",
    "根据插件ID加载插件的工厂",
    moduleName)
export class addonFactory extends baseObject implements factory {
    constructor(public rootObject?: any, public addonID?: string) {
        super();
    }

    getValue?(): any {
        if (!this.rootObject && !this.addonID)
            return findAddonByID(this.rootObject, this.addonID);
        return undefined;
    };
}

/**
 * 懒工厂
 */
@addon("懒工厂",
    "延迟加载工厂",
    moduleName)
export class lazyFactory<T> extends baseObject implements factory {
    /**
     * 构造方法
     * @param url url地址
     * @param objectName 对象名称 
     */
    constructor(public url?: string, public objectName?: string) {
        super();
    }

    getValue?(): any {
        let mod = require(`../${this.url}`);
        return mod[this.objectName];
    };
}


/**
 * 根据插件ID查找插件
 * @param rootObject 根对象
 * @param addonID 插件ID
 */
export function findAddonByID(rootObject: any, addonID: string): any {
    if (rootObject.ID == addonID) {
        return rootObject
    }

    // 查找子属性
    for (let property in rootObject) {
        let childAddon = findAddonByID(rootObject[property], addonID);
        if (childAddon)
            return childAddon;
    }

    return undefined;
}

/**
* 将对象中的类型信息取出并更改对象的类型
* @param rootObject 待获取类型的对象
*/
export function fetchAddonProtoType(rootObject: Object): void {
    // 获取子属性的类型信息
    for (let property in rootObject) {
        let properyValue = rootObject[property];
        if (properyValue instanceof Object && !(properyValue instanceof Function)) {
            fetchAddonProtoType(properyValue);
        }
    }

    // 先通过$constructor获取类型
    let classType = rootObject.constructor;
    if (!classType || classType == Object) {
        // 然后通过$type获取类型
        let typeName = rootObject[typeNamePropertyName];
        if (typeName) {
            classType = getAddonTypeByFullName(typeName);
        }
    }
    if (classType) {
        reflect.assignType(rootObject, classType);
    }
}
/**
* 设置类型信息到对象中
* @param rootObject 待设置类型的对象
*/
export function setAddonTypeInfo(addonObject: Object): void {
    // 设置子属性的类型信息
    for (let property in addonObject) {
        let properyValue = addonObject[property];
        if (properyValue instanceof Object) {
            setAddonTypeInfo(properyValue);
        }
    }
    let typeName = reflect.getTypeFullName(addonObject);
    if (typeName != "Object" && typeName != "String") {
        addonObject[typeNamePropertyName] = typeName;
    }
}

/**
* 根据类型名称获取类型
* @param typeName 类型名称
*/
export function getAddonTypeByFullName(typeName: string): any {
    return global[globalAddnPropertyName][typeName];
}

/**
* 插件序列化
* @param origion 待序列化的原始对象
*/
export function addonSerialize(origin: Object): string {
    setAddonTypeInfo(origin);
    return JSON.stringify(origin);
}

/**
    * 插件反序列化
    * @param jsonString json字符串
    */
export function addonDeserialize(jsonString: string): any {
    let result = JSON.parse(jsonString);
    fetchAddonProtoType(result);
    return result;
}

/**
    * 反序列化
    * @param classType 类型
    * @param jsonString json字符串
    */
export function addonDeserialize_T<T>(classType: type<T>, jsonString: string): T {
    let result: any = JSON.parse(jsonString);
    reflect.assignType(result, classType);
    return result;
}

/**
* 转换为字符串，如果是函数，获取函数脚本，如果是对象，获取Json
* @param origin
*/
export function toString(origin: any): string {
    if (origin instanceof Function) {
        return origin.toString();
    }
    return addonSerialize(origin);
}

/**
 * 日志记录 
 */
@addon("日志记录器", "日志记录器基类（可用于远程代理）", moduleName)
export class baseLogger extends baseObject {
    /**
     * 记录信息
     * @param date 日期
     * @param message 消息 
     * @param infoType 消息类型，可选的值：error: 错误；warning：警告；information：信息
     */
    log(date: Date, message: string, infoType: "error" | "warning" | "information" = "information"): void {

    }
}

@addon("日志服务",
    "记录普通信息和异常信息的服务",
    moduleName)
export class consoleLogger extends baseLogger {
    /**
     * 记录信息
     * @param date 日期
     * @param message 消息 
     * @param infoType 消息类型，可选的值：error: 错误；warning：警告；information：信息
     */
    log(date: Date, message: string, infoType: "error" | "warning" | "information" = "information"): void {
        logToConsole(date, message, infoType);
    }
}

/** 日志服务 */
export let serverLogger: baseLogger;
/** 日志服务 */
export let clientLogger: baseLogger = new consoleLogger();

/**
 * 记录错误到服务器
 * @param message 错误消息
 * @param infoType 消息类型，可选的值：error: 错误；warning：警告；information：信息
 */
export function logToServer(message: string, infoType: "error" | "warning" | "information" = "information") {
    if (serverLogger) {
        serverLogger.log(new Date(Date.now()), message, infoType);
    } else {
        clientLogger.log(new Date(Date.now()), `日志服务未设置，转发服务端日志：${message}`, infoType);
    }
}

/**
 * 记录错误到客户端
 * @param message 错误消息
 * @param infoType 消息类型，可选的值：error: 错误；warning：警告；information：信息
 */
export function log(message: string, infoType: "error" | "warning" | "information" = "information") {
    if (clientLogger) {
        clientLogger.log(new Date(Date.now()), message, infoType);
    } else {
        logToConsole(new Date(Date.now()), message, infoType);
    }
}

/**
 * 记录信息
 * @param date 日期
 * @param message 消息 
 * @param infoType 消息类型，可选的值：error: 错误；warning：警告；information：信息
 */
export function logToConsole(date: Date, message: string, infoType: "error" | "warning" | "information" = "information"): void {
    let dataString = `${date.toLocaleString()}`;
    if (infoType == "error") {
        console.error(`[${dataString} ${message}]`);
    } else if (infoType == "warning") {
        console.warn(`[${dataString} ${message}]`);
    }
    else {
        console.log(`[${dataString} ${message}]`);
    }
}

/**
 * 应用
 */
@addon("应用设置", "包含各种资源的主应用实体对象", moduleName)
export class application extends baseObject {
    /** 日志服务 */
    serverLogger?: baseLogger | factory;
    /** 日志服务 */
    clientLogger?: baseLogger;

    /**
     * 启动应用程序
     */
    start() {
        /** 设置服务日志记录器 */
        if (this.serverLogger)
            serverLogger = getObject(this.serverLogger);

        /** 设置客户端日志记录器 */
        if (this.clientLogger)
            clientLogger = this.clientLogger;
    }
}

@addon("列", "用于类的名称类型", moduleName)
export class dataColumn extends baseObject {
    /**
     * 字段名
     */
    name?: string;
    /**
     * 字段标题
     */
    caption?: string;
    /**
     * 字段类型
     */
    type?: "string" | "number" | "date" | "boolean";
}

@addon("字段", "用于容纳字段的名称、值等", moduleName)
export class dataField extends dataColumn {
    /**
     * 字段值
     */
    value?: any;
}

@addon("数据表", "用于容纳二维数据的表格", moduleName)
export class dataTable extends baseObject {
    /**
     * 表名
     */
    name: string;
    /**
     * 列定义
     */
    columns?: dataColumn[string];
    /**
     * 主键
     */
    primaryKey?: string[];
    /**
     * 行定义
     */
    rows? : {}[];

    /**
     * 获取字段的值
     * @param rowIndex 行号
     * @param columnName 列名 
     */
    field?(rowIndex:number, columnName: string) : any {
        return this.rows[rowIndex][columnName];
    }

    /**
     * 添加列
     * @param column 列
     */
    addColumn?(column: dataColumn) : void {
        this.columns[column.name] = column;
    }

    /**
     * 移除列
     * @param columnName 列名
     */
    removeColumn?(columnName: string) : void {
        delete this.columns[columnName];
    }

    /**
     * 清除列
     */
    clearColumns?() : void {
        delete this.columns;
    }

    /**
     * 清除数据
     */
    clearData?() : void {
        delete this.rows;
    }
}

@addon("数据集", "用于多个数据表格的数据集合", moduleName)
export class dataSet extends baseObject {
    /**
     * 数据表
     */
    tables: dataTable[string];
    
    /**
     * 添加表
     * @param table 列
     */
    addTable?(table: dataTable) : void {
        this.tables[table.name] = table;
    }

    /**
     * 移除表
     * @param tableName 表名
     */
    removeTable?(tableName: string) : void {
        delete this.tables[tableName];
    }

    /**
     * 清除表
     */
    clearTables?() : void {
        delete this.tables;
    }
}

/**
 * 数据获取器
 */
@addon("数据获取器", "数据获取器基类（可用于远程代理）", moduleName)
export class baseDataFetcher extends baseObject {
    /**
     * 查询
     * @param command 查询命令，可以是命令ID也可以是命令字符串
     * @param startIndex 起始索引
     * @param maxCount 最大行数
     * @param paramValues 参数值
     * @param resultFunc 查询结果处理函数
     */
    query(command?: string, paramValues?: {}, resultFunc? : (data: any, err?: any)=>void, startIndex: number = 0, maxCount: number = 500) {
    }
}


/**
 * 数据源
 */
@addon("数据源", "用于查询数据的数据源", moduleName)
export class dataSource extends baseObject {
    /**
     * 数据获取器
     */
    dataFetcher: baseDataFetcher | any;
    /**
     * 命令ID
     */
    commandID: string;
    /**
     * 默认参数值
     */
    defaultParamValues?: {};
    /**
     * 执行查询
     * @param startIndex 起始索引
     * @param maxCount 最大行数
     * @param paramValues 参数值
     * @param resultFunc 结果函数
     */
    doQuery(paramValues?: {}, resultFunc?: (data: any, err?: any)=>void, startIndex: number = 0, maxCount: number = 500) {
        if(this.dataFetcher) {
            throw new Error("数据获取器未初始化");
        }

        let realParamValues = {};
        if(this.defaultParamValues) {
            reflect.propertyCopy(realParamValues, this.defaultParamValues);
        }
        if(paramValues) {
            reflect.propertyCopy(realParamValues, paramValues);
        }

        // 查询数据
        let dataFetcher : baseDataFetcher = getObject(this.dataFetcher);
        dataFetcher.query(this.commandID, realParamValues, resultFunc, startIndex, maxCount);
    }
}
